package com.lyw.utils;

import com.lyw.Application;
import com.lyw.constants.GlobalVariables;
import com.lyw.enums.CharacterEnum;
import com.lyw.enums.DirectionEnum;
import com.lyw.enums.DuplicateEnum;
import com.lyw.enums.DuplicateNameEnum;
import com.lyw.factory.TimerTaskFactory;
import com.lyw.handle.*;
import org.opencv.core.*;
import org.opencv.core.Point;
import org.opencv.features2d.DescriptorMatcher;
import org.opencv.features2d.SIFT;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.DataBufferByte;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static com.lyw.constants.CommonConstants.MONSTER_HEIGHT;
import static com.lyw.constants.CommonConstants.WINDOW_HEIGHT;

public class OpenCvUtil {

  public static Rectangle characterRect;
  public static ColorConvertOp convertOp = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_sRGB), null);
  public static Mat template;
  public static Mat character;
  public static Mat monsterBackup;
  public static Mat material;
  public static Mat door;
  public static Mat miniMapRole;
  public static Mat mini_map;
  public static Mat boss_map;
  public static Mat success;
  public static Mat equipment;
  public static Mat game_over;

  static int[] arguments = new int[10];
  static int[] position = new int[4];

  private OpenCvUtil() {
  }

  public static void getRoleAndDoorPosition(Robot robot, DataFilteringAdapter filter, BufferedImage bufferedImage, int[] startPosition, TimerTaskFactory taskFactory, int height, int[] positions) {
    try {
      Mat mat = OpenCvUtil.bufferedImageToMat(bufferedImage);
      // 创建32位模板匹配结果Mat
      Mat res = new Mat(mat.rows(), mat.cols(), CvType.CV_32FC1);

      CountDownLatch count = new CountDownLatch(1);
      taskFactory.execute(() -> {
        filter.findTheTargetDoor(robot, mat, door, startPosition, positions);
        count.countDown();
      });

      Imgproc.matchTemplate(mat, character, res, Imgproc.TM_CCORR);
      Core.normalize(res, res, 0, 1, Core.NORM_MINMAX, -1, new Mat());
      Core.MinMaxLocResult characterRes = Core.minMaxLoc(res);
      positions[0] = (int) (characterRes.maxLoc.x + startPosition[0]);
      positions[1] = (int) (characterRes.maxLoc.y + startPosition[1]) + height;
      count.await();
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

  private static int[] getCharacter(Robot robot, Rectangle rectangle, Mat cMat) {
    Mat mat = OpenCvUtil.bufferedImageToMat(robot.createScreenCapture(rectangle));
    Mat res = new Mat(mat.rows(), mat.cols(), CvType.CV_32FC1);
    Imgproc.matchTemplate(mat, cMat, res, Imgproc.TM_CCORR);
    Core.normalize(res, res, 0, 1, Core.NORM_MINMAX, -1, new Mat());
    Core.MinMaxLocResult min = Core.minMaxLoc(res);
    for (int i = 0; i < res.rows(); i++) {
      for (int i1 = 0; i1 < res.cols(); i1++) {
        if (res.get(i, i1)[0] >= 0.9997) {
          return new int[]{(int) min.maxLoc.x, (int) min.maxLoc.y};
        }
      }
    }
    return new int[]{-1, -1};
  }

  public static int[] getCharacter(Mat mat, int height) {
    Mat res = new Mat(mat.rows(), mat.cols(), CvType.CV_32FC1);

    Imgproc.matchTemplate(mat, character, res, Imgproc.TM_SQDIFF_NORMED);
    int rows = res.rows();
    int cols = res.cols();
    for (int row = 0; row < rows; row++) {
      for (int col = 0; col < cols; col++) {
        if (res.get(row, col)[0] <= 0.15) {
//          return new int[]{(int) (col + rectangle.getX()), (int) (rectangle.getY() + row) + 90};
          return new int[]{col, row + height};
        }
      }
    }
    return new int[]{-1, -1};
  }

  public static int[] getCharacter(Robot robot, Rectangle rectangle, int height) {
    Mat mat = OpenCvUtil.bufferedImageToMat(robot.createScreenCapture(rectangle));
    return getCharacter(mat, height);
//    return new int[]{(int) (characterRes.maxLoc.x), (int) (characterRes.maxLoc.y) + 90};
  }
  /*public static void moveRoleToDoor(TimerTaskFactory taskFactory, Robot robot, Rectangle rectangle, DuplicateEnum duplicateInfo, int room) {
      try {
          int rows, cols, m1X = m1.cols(), m1Y = m1.rows();
          int[] key = {-1}, doorPosition = {-1, -1}, position = {0, 0};
          boolean whetherFindIt = false;
          boolean[] whetherClearance = {false};
          DataFilteringInterface filter;
          if (duplicateInfo.getRoute()[room].equals(DirectionEnum.TOP)) {
              key[0] = KeyEvent.VK_UP;
              filter = new TopProcessor();
          } else if (duplicateInfo.getRoute()[room].equals(DirectionEnum.RIGHT)) {
              key[0] = KeyEvent.VK_RIGHT;
              filter = new RightProcessor();
          } else if (duplicateInfo.getRoute()[room].equals(DirectionEnum.LEFT)) {
              key[0] = KeyEvent.VK_LEFT;
              filter = new LeftProcessor();
          } else {
              key[0] = KeyEvent.VK_DOWN;
              filter = new BottomProcessor();
          }
          MouseAndKeyEventUtil.keyPress(robot, key[0]);
          robot.delay(500);

          taskFactory.execute(() -> {
              while (SmallMapUtil.whetherClearance(robot, rectangle, duplicateInfo)) {}
              MouseAndKeyEventUtil.keyReleased(robot, key[0]);
              whetherClearance[0] = true;
              System.out.println("est");
          });

          while (true) {
              long start = System.currentTimeMillis();
              CountDownLatch count = new CountDownLatch(2);;
              Mat mat = OpenCvUtil.bufferedImageToMat(robot.createScreenCapture(rectangle));
              Mat res1 = new Mat(mat.rows(), mat.cols(), CvType.CV_32FC1);
              Mat res2 = new Mat(mat.rows(), mat.cols(), CvType.CV_32FC1);

              taskFactory.execute(() -> {
                  Imgproc.matchTemplate(mat, m2, res2, Imgproc.TM_CCORR);
                  Core.normalize(res2, res2,0, 1, Core.NORM_MINMAX, -1, new Mat());
                  count.countDown();
              });

              taskFactory.execute(() -> {
                  Imgproc.matchTemplate(mat, m1, res1, Imgproc.TM_CCORR);
                  Core.normalize(res1, res1,0, 1, Core.NORM_MINMAX, -1, new Mat());
                  count.countDown();
              });

              count.await();
              Core.MinMaxLocResult min1 = Core.minMaxLoc(res1);
              Core.MinMaxLocResult min2 = Core.minMaxLoc(res2);

              position[0] = (int) min1.maxLoc.x + m1X;
              position[1] = (int) min1.maxLoc.y + m1Y;

              rows = res2.rows();
              cols = res2.cols();

              whetherFindIt = filter.findTheTarget(robot, position, res2, rows, cols, doorPosition);
              MouseAndKeyEventUtil.keyReleased(robot, key[0]);
              if (!whetherFindIt) {
                  // 移动人物
                  filter.mobileCharacterSearchTarget(robot, key);
                  continue;
              }
              filter.mobileCharacterToDoor(robot, key, position, doorPosition);
              if (whetherClearance[0]) {
                  MouseAndKeyEventUtil.keyReleased(robot, key[0]);
              }
              System.out.println(System.currentTimeMillis() - start);
              if (!whetherFindIt) { // 没找到门
                  MouseAndKeyEventUtil.doubleClick(robot, direction.getKeyCode());
                  key[0] = direction.getKeyCode();
                  whetherPress[0] = true;
                  taskFactory.execute(() -> {
                      robot.delay(4000);
                      if (whetherPress[0]) {
                          for (int j = 0; j < 2; j++) {
                              if (direction.getKeyCode() == KeyEvent.VK_UP) {
                                  if (j == 0) {
                                      key[0] = KeyEvent.VK_LEFT;
                                      MouseAndKeyEventUtil.keyPress(robot, key[0]);
                                      MouseAndKeyEventUtil.keyReleased(robot, direction.getKeyCode());
                                  } else {
                                      MouseAndKeyEventUtil.keyPress(robot, KeyEvent.VK_RIGHT);
                                      MouseAndKeyEventUtil.keyReleased(robot, key[0]);
                                      key[0] = KeyEvent.VK_RIGHT;
                                  }
                              } else if (direction.getKeyCode() == KeyEvent.VK_RIGHT) {
                                  if (j == 0) {
                                      key[0] = KeyEvent.VK_UP;
                                      MouseAndKeyEventUtil.keyPress(robot, key[0]);
                                      MouseAndKeyEventUtil.keyReleased(robot, direction.getKeyCode());
                                  } else {
                                      MouseAndKeyEventUtil.keyPress(robot, KeyEvent.VK_DOWN);
                                      MouseAndKeyEventUtil.keyReleased(robot, key[0]);
                                      key[0] = KeyEvent.VK_DOWN;
                                  }
                              } else if (direction.getKeyCode() == KeyEvent.VK_DOWN) {
                                  if (j == 0) {
                                      key[0] = KeyEvent.VK_LEFT;
                                      MouseAndKeyEventUtil.keyPress(robot, key[0]);
                                      MouseAndKeyEventUtil.keyReleased(robot, direction.getKeyCode());
                                  } else {
                                      MouseAndKeyEventUtil.keyPress(robot, KeyEvent.VK_RIGHT);
                                      MouseAndKeyEventUtil.keyReleased(robot, key[0]);
                                      key[0] = KeyEvent.VK_RIGHT;
                                  }
                              } else if (direction.getKeyCode() == KeyEvent.VK_LEFT) {
                                  if (j == 0) {
                                      key[0] = KeyEvent.VK_UP;
                                      MouseAndKeyEventUtil.doubleClick(robot, key[0]);
                                      MouseAndKeyEventUtil.keyReleased(robot, direction.getKeyCode());
                                  } else {
                                      MouseAndKeyEventUtil.keyPress(robot, KeyEvent.VK_DOWN);
                                      MouseAndKeyEventUtil.keyReleased(robot, key[0]);
                                      key[0] = KeyEvent.VK_DOWN;
                                  }
                              }
                              robot.delay(4000);
                          }
                      }
                  });

              }
          }

      } catch (InterruptedException e) {
          e.printStackTrace();
      }
  }*/

  public static Mat bufferedImageToMat(BufferedImage image) {
    BufferedImage rgb = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
    convertOp.filter(image, rgb);
    Mat mat = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC3);
    mat.put(0, 0, ((DataBufferByte) rgb.getRaster().getDataBuffer()).getData());
    return mat;
  }

  public static void getAllPic(Mat src, Mat template) {
    Mat reshape = template.reshape(-1);
    Imgproc.threshold(src, src, 150, 255, Imgproc.THRESH_BINARY);
    Imgproc.threshold(template, template, 150, 255, Imgproc.THRESH_BINARY);
    HighGui.imshow("lea", src);
    HighGui.imshow("lea1", template);
    HighGui.waitKey(0);
    Mat result = new Mat();
    Imgproc.matchTemplate(src, template, result, Imgproc.TM_CCOEFF_NORMED);

    float[] floats = new float[3];
    Scalar red = new Scalar(0, 0, 255);

    int tRow = template.rows();
    int tCol = template.cols();

    for (int i = 0; i < result.rows(); i++) {
      for (int i1 = 0; i1 < result.cols(); i1++) {
        result.get(i, i1, floats);
        if (floats[0] > 0.8) {
          Imgproc.rectangle(src, new Point(i1, i), new Point(i1 + tCol, i + tRow), red, 2);
        }
      }
    }

    HighGui.imshow("match", src);
    HighGui.waitKey(0);
  }

  public static void highSpeed(Mat mat, CharacterEnum characterEnum, Rectangle rectangle) {
    int[] color = characterEnum.getColor();
    int rows = mat.rows();
    int cols = mat.cols();
    int channels = mat.channels();
    //像素数组大小: 行数 * 列数 * 颜色通道数
    byte[] pixels = new byte[rows * cols * channels];
    //通过一次native调用获取整个图片的像素数组
    mat.get(0, 0, pixels);
    //遍历像素数组
    int inner = cols * channels;
    int i, j;
    for (i = 0; i < rows; i++) {
      for (j = 0; j < inner; j += channels) {
        int index = i * inner + j;
                /*int r = (pixels[index + 2] & 0xff);
                int g = (pixels[index + 1] & 0xff);
                int b = (pixels[index] & 0xff);*/
        if ((pixels[index + 2] & 0xff) == color[0]
                && ((pixels[index + 1] >> 8) & 0xff) == color[1]
                && (pixels[index] & 0xff) == color[2]) {
          System.out.println(StringUtil.format("({}, {})", rectangle.getX() + j / 3, rectangle.getY() + i));
          break;
        }
      }
    }
  }

  public static void preparePng() {
    door = Imgcodecs.imread("C:\\Users\\Administrator\\Desktop\\TPlan\\TPlan\\src\\main\\resources\\images\\other\\door.png");
    template = Imgcodecs.imread("C:\\Users\\Administrator\\Desktop\\TPlan\\TPlan\\src\\main\\resources\\images\\templates\\monster.png");
    character = Imgcodecs.imread("C:\\Users\\Administrator\\Desktop\\TPlan\\TPlan\\src\\main\\resources\\images\\characters\\swordGod.jpg");
    monsterBackup = Imgcodecs.imread("C:\\Users\\Administrator\\Desktop\\TPlan\\TPlan\\src\\main\\resources\\images\\templates\\monster_back_template.png");
    material = Imgcodecs.imread("C:\\Users\\Administrator\\Desktop\\TPlan\\TPlan\\src\\main\\resources\\images\\templates\\material.png");
    miniMapRole = Imgcodecs.imread("C:\\Users\\Administrator\\Desktop\\TPlan\\TPlan\\src\\main\\resources\\images\\characters\\mini_character.png");
    mini_map = Imgcodecs.imread("C:\\Users\\Administrator\\Desktop\\TPlan\\TPlan\\src\\main\\resources\\images\\other\\mini_map.png");
    boss_map = Imgcodecs.imread("C:\\Users\\Administrator\\Desktop\\TPlan\\TPlan\\src\\main\\resources\\images\\characters\\boss.png");
    success = Imgcodecs.imread("C:\\Users\\Administrator\\Desktop\\TPlan\\TPlan\\src\\main\\resources\\images\\characters\\success.png");
    equipment = Imgcodecs.imread("C:\\Users\\Administrator\\Desktop\\TPlan\\TPlan\\src\\main\\resources\\images\\other\\equipment.png");
    game_over = Imgcodecs.imread("C:\\Users\\Administrator\\Desktop\\TPlan\\TPlan\\src\\main\\resources\\images\\other\\gameover.png");
  }

  public static void matchTemplateMonsterAndRole(int[] startPosition,
                                                 TimerTaskFactory taskFactory,
                                                 Mat mat,
                                                 int[] positions,
                                                 int height) throws InterruptedException {
    // 创建32位模板匹配结果Mat
    Mat res2 = new Mat(mat.rows(), mat.cols(), CvType.CV_32FC1);

    CountDownLatch count = new CountDownLatch(1);
    taskFactory.execute(() -> {
      OpenCvUtil.matchMonsterExceptionTemplate(startPosition,
              mat,
              positions);
      count.countDown();
    });

    /*Imgproc.matchTemplate(mat, character, res2, Imgproc.TM_CCORR);
    Core.normalize(res2, res2,0, 1, Core.NORM_MINMAX, -1, new Mat());
    Core.MinMaxLocResult characterRes = Core.minMaxLoc(res2);
    positions[0] = (int) (characterRes.maxLoc.x + startPosition[0]);
    positions[1] = (int) (characterRes.maxLoc.y + startPosition[1]) + height + WINDOW_HEIGHT;*/
    Imgproc.matchTemplate(mat, character, res2, Imgproc.TM_SQDIFF_NORMED);
    int rows = res2.rows();
    int cols = res2.cols();

    for (int row = 0; row < rows; row++) {
      for (int col = 0; col < cols; col++) {
        if (res2.get(row, col)[0] <= 0.08) {
          positions[0] = col + startPosition[0];
          positions[1] = row + startPosition[1] + height + WINDOW_HEIGHT;
          return;
        }
      }
    }
    count.await();
  }

  public static void matchMonsterExceptionTemplate(int[] startPosition, BufferedImage screenCapture, int[] positions) {
    matchMonsterExceptionTemplate(startPosition, OpenCvUtil.bufferedImageToMat(screenCapture), positions);
  }

  public static void matchMonsterExceptionTemplate(int[] startPosition, Mat mat, int[] positions) {
    // 创建32位模板匹配结果Mat
    Mat result = new Mat(mat.cols(), mat.rows(), CvType.CV_32FC1);
//    Imgproc.matchTemplate(mat, monsterBackup, result, Imgproc.TM_CCORR_NORMED);
    Imgproc.matchTemplate(mat, monsterBackup, result, Imgproc.TM_SQDIFF_NORMED);
//    if (mmr.maxVal > 0.9) {
    for (int j = 0; j < result.cols(); j++) {
      for (int i = 0; i < result.rows(); i++) {
        if (result.get(i, j)[0] <= 0.06) {
          positions[2] = j + startPosition[0];
          positions[3] = i + startPosition[1] + MONSTER_HEIGHT + WINDOW_HEIGHT;
          /*Point point = new Point(j, i);
          Imgproc.rectangle(mat, point, new Point(point.x + monsterBackup.cols(), point.y + monsterBackup.rows()), new Scalar(0, 0, 255), 1, Imgproc.LINE_AA);
          HighGui.imshow("a", mat);
          HighGui.waitKey(0);*/
          return;
        }
      }
    }
    positions[2] = -1;
    positions[3] = -1;
  }
  /*public static void matchMonsterExceptionTemplate(int[] startPosition, Mat mat, int[] positions) {
    int width = mat.cols() - monsterBackup.cols() + 1;
    int height = mat.rows() - monsterBackup.rows() + 1;

    // 创建32位模板匹配结果Mat
    Mat result = new Mat(width, height, CvType.CV_32FC1);
    Imgproc.matchTemplate(mat, monsterBackup, result, Imgproc.TM_SQDIFF);
//    Core.normalize(result, result, 0.8, 1, Core.NORM_MINMAX, -1, new Mat());
    Core.MinMaxLocResult mmr = Core.minMaxLoc(result);
    if (mmr.maxVal > 0.9) {
      for (int j = 0; j < result.cols(); j++) {
        for (int i = 0; i < result.rows(); i++) {
          if (result.get(i, j)[0] < 0.05) {
            positions[2] = j + startPosition[0];
            positions[3] = i + startPosition[1] + MONSTER_HEIGHT + WINDOW_HEIGHT;
            return;
          }
        }
      }
      positions[2] = -1;
      positions[3] = -1;
    }
  }*/

  public static void getRoleAndMonsterPosition(int[] startPosition, TimerTaskFactory taskFactory, BufferedImage bufferedImage, int height, int[] positions) {
    try {
      Mat mat = OpenCvUtil.bufferedImageToMat(bufferedImage);
      // 创建32位模板匹配结果Mat
      Mat res2 = new Mat(mat.rows(), mat.cols(), CvType.CV_32FC1);

      // 创建32位模板匹配结果Mat
      CountDownLatch count = new CountDownLatch(1);
      taskFactory.execute(() -> {
//        Imgproc.matchTemplate(mat, template, res1, Imgproc.TM_SQDIFF_NORMED);
        OpenCvUtil.matchMonsterExceptionTemplate(startPosition,
                mat,
                positions);
        count.countDown();
      });

      Imgproc.matchTemplate(mat, character, res2, Imgproc.TM_CCORR);
      Core.normalize(res2, res2, 0, 1, Core.NORM_MINMAX, -1, new Mat());
      Core.MinMaxLocResult characterRes = Core.minMaxLoc(res2);
      positions[0] = (int) (characterRes.maxLoc.x + startPosition[0]);
      positions[1] = (int) (characterRes.maxLoc.y + startPosition[1]) + height + WINDOW_HEIGHT;

      count.await();
      /*Core.MinMaxLocResult monster = Core.minMaxLoc(res1);
      if (monster.maxVal > 0.9) {
        for (arguments[0] = 0; arguments[0] < res1.cols(); arguments[0]++) {
          for (arguments[1] = 0; arguments[1] < res1.rows(); arguments[1]++) {
            if (res1.get(arguments[1], arguments[0])[0] < 0.05) {
              positions[2] = arguments[0] + startPosition[0];
              positions[3] = arguments[1] + startPosition[1] + MONSTER_HEIGHT + WINDOW_HEIGHT;
              break;
            }
          }
          if (arguments[1] != res1.rows()) {
            break;
          }
        }
      }*/
//      System.out.println(positions[0] + ", " + positions[1] + " --- " + positions[2] + ", " + positions[3]);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

  public static void matchTemplate(TimerTaskFactory taskFactory, BufferedImage image) throws InterruptedException {

    Mat mat = OpenCvUtil.bufferedImageToMat(image);
    Mat res1 = new Mat(mat.rows(), mat.cols(), CvType.CV_32FC1);
    Mat res2 = res1.clone();
    CountDownLatch count = new CountDownLatch(1);
    long start = System.currentTimeMillis();

    taskFactory.execute(() -> {
      Imgproc.matchTemplate(mat, template, res1, Imgproc.TM_SQDIFF_NORMED);
      count.countDown();
    });

    Imgproc.matchTemplate(mat, character, res2, Imgproc.TM_CCORR);
    Core.normalize(res2, res2, 0, 1, Core.NORM_MINMAX, -1, new Mat());
    Core.MinMaxLocResult characterRes = Core.minMaxLoc(res2);
    position[2] = (int) characterRes.maxLoc.x;
    position[3] = (int) characterRes.maxLoc.y;

    count.await();

    Core.MinMaxLocResult monster = Core.minMaxLoc(res1);
    if (monster.maxVal > 0.9) {
      for (arguments[0] = 0; arguments[0] < res1.cols(); arguments[0]++) {
        for (arguments[1] = 0; arguments[1] < res1.rows(); arguments[1]++) {
          if (res1.get(arguments[1], arguments[0])[0] < 0.05) {
            position[0] = arguments[0];
            position[1] = arguments[1];
            break;
          }
        }
        if (arguments[1] != res1.rows()) {
          break;
        }
      }
    }
    System.out.println(System.currentTimeMillis() - start);

    if (position[0] > position[2] - 20 && position[0] < position[2] + 20) {
      System.out.println("xxxxxxxxxxxxxx");
    }

    if (position[1] > position[3] - 20 && position[1] < position[3] + 20) {
      System.out.println("yyyyyyyyyyyyyy");
    }

    System.out.println(position[0] + ", " + position[1] + " --- " + position[2] + ", " + position[3]);
    /*// 创建32位模板匹配结果Mat
    Mat result = new Mat(width, height, CvType.CV_32FC1);
    Imgproc.matchTemplate(mat, template, result, Imgproc.TM_SQDIFF_NORMED);
//    Core.normalize(result, result, 0.8, 1, Core.NORM_MINMAX, -1, new Mat());
    Core.MinMaxLocResult mmr = Core.minMaxLoc(result);
    if (mmr.minVal < 0.05) {
      for (int j = 0; j < result.cols(); j++) {
        for (int i = 0; i < result.rows(); i++) {
          if (result.get(i, j)[0] < 0.05) {
            System.out.println(j + ", " + (i + 121));
            return;
          }
        }
      }
    }*/
  }

  public static void matchTemplate(File picFile) {
    String path1 = "C:\\Users\\Administrator\\Desktop\\template123.png";
    Mat mat = null;
    try {
      mat = OpenCvUtil.bufferedImageToMat(ImageIO.read(new File(path1)));
    } catch (IOException e) {
      e.printStackTrace();
    }
    Mat template = Imgcodecs.imread("C:\\Users\\Administrator\\Desktop\\TPlan\\TPlan\\src\\main\\resources\\images\\templates\\monster_back_template.png");

    int width = mat.cols() - template.cols() + 1;
    int height = mat.rows() - template.rows() + 1;

    // 创建32位模板匹配结果Mat
    Mat result = new Mat(width, height, CvType.CV_32FC1);
    Imgproc.matchTemplate(mat, template, result, Imgproc.TM_SQDIFF);
    Core.MinMaxLocResult mmr = Core.minMaxLoc(result);
    if (mmr.maxVal > 0.9) {
      for (int j = 0; j < result.cols(); j++) {
        for (int i = 0; i < result.rows(); i++) {
          if (result.get(i, j)[0] < 0.1) {
            Point point = new Point(j, i);
            System.out.println(j + ", " + i);
            Imgproc.rectangle(mat, point, new Point(point.x + template.cols(), point.y + template.rows()), new Scalar(0, 0, 255), 1, Imgproc.LINE_AA);
          }
        }
      }
      String file = picFile.getAbsolutePath().substring(picFile.getAbsolutePath().lastIndexOf("\\", 50) + 1);
      String path = Application.matches + File.separator + file.substring(0, file.lastIndexOf("\\") + 1);
      try {
        Files.createDirectories(Paths.get(path));
      } catch (IOException e) {
        e.printStackTrace();
      }
      Imgcodecs.imwrite(path + picFile.getName(), mat);
    }
  }

  /**
   * 比较两个图片有哪些发生改变了
   */
  public static void comparePicDifferent(String origin, String templ) {
    // 加载原始图像
    System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    System.setProperty("java.awt.headless", "false");

    Mat src = Imgcodecs.imread(origin, 1);
    Mat dst = Imgcodecs.imread(templ, 1);
    Mat mat1_gray = new Mat();
    Imgproc.cvtColor(src, mat1_gray, Imgproc.COLOR_BGR2GRAY);
    Mat mat2_gray = new Mat();
    Imgproc.cvtColor(dst, mat2_gray, Imgproc.COLOR_BGR2GRAY);
    mat1_gray.convertTo(mat1_gray, CvType.CV_32F);
    mat2_gray.convertTo(mat2_gray, CvType.CV_32F);
    double result = Imgproc.compareHist(mat1_gray, mat2_gray, Imgproc.CV_COMP_CORREL);
    if (result == 1) {
      // 此处结果为1则为完全相同
      return;
    }
    System.out.println("相似度数值为:" + result);
    Mat mat_result = new Mat();
    //计算两个灰度图的绝对差值，并输出到一个Mat对象中
    Core.absdiff(mat1_gray, mat2_gray, mat_result);
    //将灰度图按照阈值进行绝对值化
    mat_result.convertTo(mat_result, CvType.CV_8UC1);
    List<MatOfPoint> mat2_list = new ArrayList<MatOfPoint>();
    Mat mat2_hi = new Mat();
    //寻找轮廓图
    Imgproc.findContours(mat_result, mat2_list, mat2_hi, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
    Mat mat_result1 = src;
    Mat mat_result2 = dst;
    //使用红色标记不同点
    System.out.println(mat2_list.size());

    for (MatOfPoint matOfPoint : mat2_list) {
      Rect rect = Imgproc.boundingRect(matOfPoint);
      Imgproc.rectangle(mat_result1, rect.tl(), rect.br(), new Scalar(0, 0, 255), 2);
      Imgproc.rectangle(mat_result2, rect.tl(), rect.br(), new Scalar(0, 0, 255), 2);
    }

    Imgcodecs.imwrite("1.png", mat_result1);
    Imgcodecs.imwrite("2.png", mat_result2);
  }

  public static void findMateInfo(String path) {
    Mat mat = Imgcodecs.imread(path);
    int width = mat.cols() - monsterBackup.cols() + 1;
    int height = mat.rows() - monsterBackup.rows() + 1;

    // 创建32位模板匹配结果Mat
    Mat result = new Mat(width, height, CvType.CV_32FC1);
    Imgproc.matchTemplate(mat, monsterBackup, result, Imgproc.TM_CCORR_NORMED);
//    Core.normalize(result, result, 0.5, 0.1, Core.NORM_MINMAX, -1, new Mat());
//    if (mmr.maxVal > 0.9) {
    for (int j = 0; j < result.cols(); j++) {
      for (int i = 0; i < result.rows(); i++) {
        if (result.get(i, j)[0] > 0.991) {
          Point point = new Point(j, i);
          Imgproc.rectangle(mat, point, new Point(point.x + monsterBackup.cols(), point.y + monsterBackup.rows()), new Scalar(0, 0, 255), 1, Imgproc.LINE_AA);
        }
      }
    }
    HighGui.imshow("a", mat);
    HighGui.waitKey(0);
//    }
  }

  public static void findMateInfo(BufferedImage bufferedImage) {
    Mat mat = bufferedImageToMat(bufferedImage);
    int width = mat.cols() - monsterBackup.cols() + 1;
    int height = mat.rows() - monsterBackup.rows() + 1;

    // 创建32位模板匹配结果Mat
    Mat result = new Mat(width, height, CvType.CV_32FC1);
    /*Imgproc.matchTemplate(mat, monsterBackup, result, Imgproc.TM_SQDIFF_NORMED);
    Core.MinMaxLocResult mmr = Core.minMaxLoc(result);
//    if (mmr.maxVal > 0.9) {
      for (int j = 0; j < result.cols(); j++) {
        for (int i = 0; i < result.rows(); i++) {
          if (result.get(i, j)[0] <= 0.0333) {
            Point point = new Point(j, i);
            Imgproc.rectangle(mat, point, new Point(point.x + monsterBackup.cols(), point.y + monsterBackup.rows()), new Scalar(0, 0, 255), 1, Imgproc.LINE_AA);
          }
        }
      }
//    }*/
    Imgproc.matchTemplate(mat, monsterBackup, result, Imgproc.TM_CCOEFF_NORMED);
    Core.MinMaxLocResult mmr = Core.minMaxLoc(result);
    if (mmr.maxVal > 0.9) {
      for (int j = 0; j < result.cols(); j++) {
        for (int i = 0; i < result.rows(); i++) {
          if (result.get(i, j)[0] > 0.9) {
            Point point = new Point(j, i);
            Imgproc.rectangle(mat, point, new Point(point.x + template.cols(), point.y + template.rows()), new Scalar(0, 0, 255), 1, Imgproc.LINE_AA);
            break;
          }
        }
      }
    }
    HighGui.imshow("a", mat);
    HighGui.waitKey(10);
  }

  public static void prepareCharacterArea(Rectangle rectangle) {

    characterRect = new Rectangle((int) rectangle.getX(), (int) rectangle.getY() + 121,
            (int) rectangle.getWidth(), (int) rectangle.getHeight() - 121);
  }

  static int width = 107;
  static int height = 137;

  public static void resize() {
    System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    File folders = new File("C:\\Users\\Administrator\\Desktop\\test\\img_origin");
    String[] files = folders.list();
    String dstPath = "C:\\Users\\Administrator\\Desktop\\test\\dst";

    for (int i = 0; i < files.length; i++) {
      Mat mat = Imgcodecs.imread(folders.getAbsolutePath() + File.separator + files[i]);
      Mat dst = new Mat();
      Size size = new Size(width, height);
      Imgproc.resize(mat, dst, size);
      Imgcodecs.imwrite(dstPath + File.separator + files[i].substring(files[i].lastIndexOf("\\") + 1), dst);
    }
  }

  public static void loadConfig() {
    File dst = new File("C:\\Users\\Administrator\\Desktop\\test\\0");
//    File neg = new File("C:\\Users\\Administrator\\Desktop\\test\\neg");
    File neg = null;
    if (dst.exists()) {
      StringBuffer sb = new StringBuffer();
      File[] files = dst.listFiles();
      List<File> collect = Arrays.stream(files)
              .filter(item -> "png".equalsIgnoreCase(item.getName().substring(item.getName().length() - 3)))
              .collect(Collectors.toList());
      for (int i = 0; i < collect.size(); i++) {
        BufferedImage read = null;
        try {
          read = ImageIO.read(collect.get(i));
        } catch (IOException e) {
          e.printStackTrace();
        }
        sb.append(collect.get(i).getAbsolutePath());
        sb.append(" ");
        sb.append("1 ");
        sb.append("0 0 ");
        sb.append(read.getWidth());
        sb.append(" ");
        sb.append(read.getHeight());
        sb.append("\n");
      }
      FileOutputStream os = null;
      try {
        os = new FileOutputStream(new File(dst.getAbsolutePath() + File.separator + "info.txt"));
        os.write(sb.toString().getBytes());
        os.flush();
        os.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }

    /*if (neg.exists()) {
      StringBuffer sb = new StringBuffer();
      File[] files = neg.listFiles();
      List<File> collect = Arrays.stream(files).filter(item -> "png".equalsIgnoreCase(item.getName().substring(item.getName().length() - 3)) || "jpg".equalsIgnoreCase(item.getName().substring(item.getName().length() - 3)))
              .collect(Collectors.toList());
      for (int i = 0; i < collect.size(); i++) {
        sb.append(collect.get(i).getAbsolutePath());
        sb.append("\n");
      }
      FileOutputStream os = null;
      try {
        os = new FileOutputStream(new File(neg.getAbsolutePath() + File.separator + "bg.txt"));
        os.write(sb.toString().getBytes());
        os.flush();
        os.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }*/
  }

  public static void handlePicSize() {
    String path = "C:\\Users\\Administrator\\Desktop\\test\\neg";
    File folder = new File(path);
    File[] files = folder.listFiles();
    for (File file : files) {
      Mat mat = Imgcodecs.imread(file.getAbsolutePath());
      Imgproc.cvtColor(mat, mat, Imgproc.COLOR_BGR2GRAY);
      Imgproc.resize(mat, mat, new Size(48, 22));
      Imgcodecs.imwrite(file.getAbsolutePath(), mat);
    }
  }

  public static void getMiniMapCharacter(BufferedImage screenCapture, int[] position) {
    Mat mat = bufferedImageToMat(screenCapture);
//    Mat template = Imgcodecs.imread("C:\\Users\\Administrator\\Desktop\\1.png");
    Mat result = new Mat(mat.rows(), mat.cols(), CvType.CV_32FC1);
    Imgproc.matchTemplate(mat, miniMapRole, result, Imgproc.TM_SQDIFF_NORMED);
    for (int j = 0; j < result.cols(); j++) {
      for (int i = 0; i < result.rows(); i++) {
        if (result.get(i, j)[0] < 0.01) {
          position[0] = j;
          position[1] = i;
          return;
        }
      }
    }
    position[0] = -1;
    position[1] = -1;
  }

  public static int[] getMiniCharacter(Mat mat) {
    Mat result = new Mat(mat.rows(), mat.cols(), CvType.CV_32FC1);
    Imgproc.matchTemplate(mat, miniMapRole, result, Imgproc.TM_SQDIFF_NORMED);
    for (int j = 0; j < result.cols(); j++) {
      for (int i = 0; i < result.rows(); i++) {
        if (result.get(i, j)[0] <= 0.1) {
          return new int[]{j, i};
        }
      }
    }

    // TODO 裂缝
    return new int[]{-1, -1};
  }

  /**
   * 是否通关
   */
  public static boolean matchMiniMapWhetherClearance(Robot robot) {
    for (int i = 0; i < 10; i++) {
      Mat mat = bufferedImageToMat(robot.createScreenCapture(SmallMapUtil.mapRectangle));
      Mat result = new Mat(mat.rows(), mat.cols(), CvType.CV_32FC1);
      Imgproc.matchTemplate(mat, success, result, Imgproc.TM_SQDIFF_NORMED);
      Core.MinMaxLocResult mmr = Core.minMaxLoc(result);
      if (mmr.minVal <= 0.05) {
        return true;
      }
    }
    return false;
  }

  public static int[] getBossPosition(Mat mat, int size) {
    Mat result = new Mat(mat.rows(), mat.cols(), CvType.CV_32FC1);
    Imgproc.matchTemplate(mat, boss_map, result, Imgproc.TM_SQDIFF_NORMED);
    for (int j = 0; j < result.cols(); j++) {
      for (int i = 0; i < result.rows(); i++) {
        if (result.get(i, j)[0] <= 0.2) {
          return new int[]{j / size, i / size};
        }
      }
    }
    return new int[]{-1, -1};
  }

  public static int[] matchEquipmentGetSimplePosition(TimerTaskFactory taskFactory, Robot robot, Rectangle rectangle, int height) {

    Mat mat = bufferedImageToMat(robot.createScreenCapture(rectangle));
    return matchEquipmentGetSimplePosition(taskFactory, mat, height);
  }
  public static int[] matchEquipmentGetSimplePosition(TimerTaskFactory taskFactory, Mat mat, int height) {
    int[] positions = {-1, -1, -1, -1};

    try {
      CountDownLatch count = new CountDownLatch(1);
      taskFactory.execute(() -> {
        int[] character = OpenCvUtil.getCharacter(mat, height);
        positions[0] = character[0];
        positions[1] = character[1];
        count.countDown();
      });
      Mat result = new Mat(mat.rows(), mat.cols(), CvType.CV_32FC1);

      Imgproc.matchTemplate(mat, equipment, result, Imgproc.TM_SQDIFF_NORMED);
      int rows = result.rows();
      int cols = result.cols();

      for (int row = 0; row < rows; row++) {
        for (int col = 0; col < cols; col++) {
          if (result.get(row, col)[0] <= 0.12) {
            positions[2] = col + 10;
            positions[3] = row;
            break;
          }
        }
      }
      count.await();
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    return positions;
  }

  public static List<int[]> matchEquipment(Mat mat) {
    List<int[]> r = new ArrayList<>();
    Mat result = new Mat(mat.rows(), mat.cols(), CvType.CV_32FC1);
    Imgproc.matchTemplate(mat, equipment, result, Imgproc.TM_SQDIFF_NORMED);
    int rows = result.rows();
    int cols = result.cols();

    for (int row = 0; row < rows; row++) {
      for (int col = 0; col < cols; col++) {
        if (result.get(row, col)[0] <= 0.028) {
          r.add(new int[]{col, row});
          break;
        }
      }
    }
    return r;
  }

  public static void moveToDest(Robot robot, Rectangle rectangle, int[] equipment, Supplier<int[]> supplier, int height) throws Exception {
    int[] keycodes = {-1, -1};
    int threshold = 20; // 模糊值
    int[] character = OpenCvUtil.getCharacter(robot, rectangle, height);
    CharacterUtil.mobileCharacter(character, equipment, keycodes);
    boolean[] flag = {false, false, false};
    int[] ints = supplier.get();

    while (true) {
      int xAbs = Math.abs(ints[0] - ints[2]);
      int yAbs = Math.abs(ints[1] - ints[3]);
      if (!flag[0] && xAbs <= threshold) {
        TimeUnit.MILLISECONDS.sleep(20);
        MouseAndKeyEventUtil.keyReleased(keycodes[0]);
        flag[0] = true;
      }
      if (!flag[1] && yAbs <= threshold) {
        TimeUnit.MILLISECONDS.sleep(20);
        MouseAndKeyEventUtil.keyReleased(keycodes[1]);
        flag[1] = true;
      }

      if (flag[0] && flag[1]) {
        System.out.println("移动到了目标地方！");
        MouseAndKeyEventUtil.keyReleased(null);
        return;
      }
      ints = supplier.get();
    }
  }

  public static boolean whetherClearance(Mat mat) {
//    mat = Imgcodecs.imread("C:\\Users\\Administrator\\Desktop\\over.png");
    Mat result = new Mat(mat.rows(), mat.cols(), CvType.CV_32FC1);
    Imgproc.matchTemplate(mat, game_over, result, Imgproc.TM_SQDIFF_NORMED);
    for (int j = 0; j < result.cols(); j++) {
      for (int i = 0; i < result.rows(); i++) {
        if (result.get(i, j)[0] <= 0.3) {
          /*Point point = new Point(j, i);
          Imgproc.rectangle(mat, point, new Point(point.x + game_over.cols(), point.y + game_over.rows()), new Scalar(0, 0, 255), 1, Imgproc.LINE_AA);
          HighGui.imshow("a", mat);
          HighGui.waitKey(0);*/
          return true;
        }
      }
    }
    return false;
  }

  public static void dynamicCharacterPosition(Robot robot, int height) {
    Mat mat = OpenCvUtil.bufferedImageToMat(robot.createScreenCapture(OpenCvUtil.characterRect));
    Mat result = new Mat(mat.rows(), mat.cols(), CvType.CV_32FC1);
    Imgproc.matchTemplate(mat, OpenCvUtil.character, result, Imgproc.TM_SQDIFF_NORMED);
    Core.MinMaxLocResult mmr = Core.minMaxLoc(result);
    GlobalVariables.POSITIONS[0] = (int) mmr.minLoc.x;
    GlobalVariables.POSITIONS[1] = (int) mmr.minLoc.y + height + WINDOW_HEIGHT;
    System.out.println(GlobalVariables.POSITIONS[0] + ", " + GlobalVariables.POSITIONS[1]);
    /*int rows = result.rows();
    int cols = result.cols();

    for (int row = 0; row < rows; row++) {
      for (int col = 0; col < cols; col++) {
        if (result.get(row, col)[0] <= 0.08) {
          GlobalVariables.POSITIONS[0] = col;
          GlobalVariables.POSITIONS[1] = row + 90 + WINDOW_HEIGHT;
          System.out.println(GlobalVariables.POSITIONS[0] + ", " + GlobalVariables.POSITIONS[1]);
          return;
        }
      }
    }*/
  }
}
